<template>
  <section class="main-section">
    <div class="btn-wrapper">
      <a-button class="btn-type" type="danger" @click="generate()">生成密钥</a-button>
      <a-button class="btn-type" type="primary" @click="encrypt()">加密</a-button>
      <a-button class="btn-type" type="primary" @click="decrypt()">解密</a-button>
    </div>

    <div class="text-wrapper">
      Key ( 默认生成256位随机Key, 可自定义Key ) :
      <a-textarea placeholder="S-Box Key" :rows="4" :value="key" allowClear/>
    </div>
    <a-divider type="vertical"/>

    <div>
      明文:
      <a-input v-model:value="plainText" placeholder="明文"/>
    </div>
    <a-divider type="vertical"/>

    <div>
      <span class="text-wrapper">
        密文字节数组:
      </span>
      <a-input v-model:value="cipherTextArray" placeholder="密文字节数组"/>
      <span class="text-wrapper">
        密文:
      </span>
      <a-input v-model:value="cipherText" placeholder="密文"/>
    </div>
    <a-divider type="vertical"/>
  </section>
</template>

<script>
import {decrypt, encrypt} from "../../api/rc4";

export default {
  name: "RC4",
  data() {
    return {
      // S-BOX Key
      key: '',
      // 明文
      plainText: '',
      // 密文字节数组
      cipherTextArray: [],
      // 密文
      cipherText: ''
    }
  },
  methods: {
    // 生成SBoxKey
    generate() {
      let key = this.randomString()
      console.log(`key: ${key}`)
      this.key = key
    },
    // 加密
    encrypt() {
      let key = this.key
      let plainText = this.plainText

      if (key.length === 0) {
        this.$message.error("Key不能为空")
        return
      }

      if (plainText.length === 0) {
        this.$message.error("明文不能为空")
        return
      }

      encrypt({
        "plain": plainText,
        "key": key
      }).then(res => {
        let result = res.data;
        console.log(`result: ${result}`)

        if (result.length === 0) {
          this.$message.error(`RC4加密失败`)
          return
        }

        this.cipherTextArray = result
        this.$message.success(`RC4加密成功, ${this.cipherTextArray}`)
        // 密文字节数组转字符串
        this.cipherText = this.byteToString(this.cipherTextArray)
        this.plainText = ''
      }).catch(err => {
        console.error(err)
        this.$message.error(`RC4加密失败, 原因: ${err}`)
      })
    },
    // 解密
    decrypt() {
      let key = this.key
      let cipherText = this.cipherTextArray

      if (key.length === 0) {
        this.$message.error("Key不能为空")
        return
      }

      if (cipherText.length === 0) {
        this.$message.error("密文不能为空")
        return
      }

      decrypt({
        "cipher": cipherText,
        "key": key
      }).then(res => {
        let result = res.data;
        console.log(`result: ${result}`)

        if (result.length === 0) {
          this.$message.error(`RC4解密失败`)
          return
        }

        this.plainText = result
        this.$message.success(`RC4解密成功, ${this.plainText}`)
        this.cipherTextArray = ''
        this.cipherText = ''
      }).catch(err => {
        console.error(err)
        this.$message.error(`RC4解密失败, 原因: ${err}`)
      })
    },
    // 生成随机值
    randomString() {
      let str = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890+-,/|"
      console.log(`str: ${str}`)
      let a = str.length
      let n = ""
      for (let i = 0; i < 256; i++) {
        n += str.charAt(Math.floor(Math.random() * a))
      }
      return n
    },
    // 字节数组转字符串
    byteToString(arr) {
      if(typeof arr === 'string') {
        return arr
      }
      let str = '',
          _arr = arr
      for(let i = 0; i < _arr.length; i++) {
        let one = _arr[i].toString(2),
            v = one.match(/^1+?(?=0)/)
        if(v && one.length === 8) {
          let bytesLength = v[0].length;
          let store = _arr[i].toString(2).slice(7 - bytesLength)
          for(let st = 1; st < bytesLength; st++) {
            store += _arr[st + i].toString(2).slice(2)
          }
          str += String.fromCharCode(parseInt(store, 2))
          i += bytesLength - 1
        } else {
          str += String.fromCharCode(_arr[i])
        }
      }
      return str
    }
  }
}
</script>

<style scoped>
.btn-wrapper {
  margin: 30px;
}

.btn-type {
  margin: 20px;
  line-height: 24px;
  font-size: 20px;
}

.main-section {
  margin-top: 30px;
}

.text-wrapper {
  margin: 20px;
}
</style>
